package foundation.fileUtil;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.Namespace;
import org.jdom2.filter.Filter;
import org.jdom2.filter.Filters;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.jdom2.xpath.XPathBuilder;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
import org.jdom2.xpath.jaxen.JaxenXPathFactory;

public class XMLFileUtil {

	// XML文档根元素
	private Element root = null;
	private Document document = null;

	/**
	 * 构造函数
	 * @param xmlFile:XML文件
	 */
	public XMLFileUtil(File xmlFile) {
		SAXBuilder saxBuilder = new SAXBuilder();
		try {
			document = saxBuilder.build(xmlFile);
			root = document.getRootElement();
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 根据结点路径读取以该结点为根的所有XML元素
	 * 
	 * @param pathName
	 *            ：XML文件中结点的路径
	 * @return：结点对应的XML元素列表（包括子元素）
	 * @throws JDOMException
	 *             ：抛出异常
	 */
	public List<Element> readNode(String pathName) throws JDOMException {

		Filter<Element> filter = Filters.element();

		XPathBuilder<Element> builder = new XPathBuilder<Element>(pathName,
				filter);

		XPathFactory factory = JaxenXPathFactory.instance();

		XPathExpression<Element> exp = builder.compileWith(factory);

		return exp.diagnose(root, false).getResult();

	}

	//readNode方法为新增方法
	
		/**
		 * @param pathName:可带命名空间前缀的路径名(如：fjnu:/cs)
		 * @param prefix:前缀（如:fjnu)
		 * @param url:前缀对应的统一资源定位符(如：http://www.fjnu.edu.cn)
		 * @return：结点对应的XML元素列表（包括子元素）
		 * @throws JDOMException
		 *             ：抛出异常
		 */
		public List<Element> readNode(String pathName,String prefix,String url) throws JDOMException {

			Filter<Element> filters = Filters.element();
		
			XPathBuilder<Element> builder = new XPathBuilder<Element>(pathName,
					filters);
		
			Namespace ns = Namespace.getNamespace(prefix,url);
			
			builder.setNamespace(ns);

			XPathFactory factory = JaxenXPathFactory.instance();

			XPathExpression<Element> exp = builder.compileWith(factory);

			return exp.diagnose(root, false).getResult();

		}
	
	/**
	 * 将内存中对应的XML结点树写入到指定的文件
	 * 
	 * @param fileName
	 *            ：XML文件名称
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public synchronized void write(String fileName)
			throws FileNotFoundException, IOException {
		 Format format = Format.getCompactFormat(); 
		   format.setEncoding("GBk"); //设置xml文件的字符为GBk 
		   //设置缩进 此行代码决定是否换行
		   format.setIndent("  "); 
		XMLOutputter outer = new XMLOutputter(format);
		FileOutputStream fileOutputStream=new FileOutputStream(fileName);
		outer.output(document, fileOutputStream);
		fileOutputStream.flush();
	}

	/**
	 * 关闭打开的文件
	 */
	public void close(String fileName){
		if(document!=null){
			document.detachRootElement();
			document=null;
			root=null;
		}
	}
	
	/**
	 * 比较两个XML文件内容是否相同
	 * @param desXMLFileName
	 *            ：目标XML文件名
	 * @return：返回当前和目标XML文件的内容是否相同
	 */
	public boolean compareFile(File desXMLFile) {
		boolean result = false;

		SAXBuilder desSaxBuilder = new SAXBuilder();
		try {
			Document DesDocument = desSaxBuilder.build(desXMLFile);
			
			Element desRoot = DesDocument.getRootElement();
			result = compareElement(root, desRoot);
		} catch (JDOMException e) {
			result = false;
		} catch (IOException e) {
			result = false;
		}

		return result;

	}

	/**
	 * 根据两个根结点，比较两个XML文件的内容是否相同
	 * @param srcRoot
	 * @param desRoot
	 * @return
	 */
	private boolean compareElement(Element srcRoot, Element desRoot) {

		boolean result = false;
		// 判断元素的属性是否相同
		if (compareAttribute(srcRoot, desRoot)) {
			List<Element> srcChildElements = srcRoot.getChildren();
			List<Element> desChildElements = desRoot.getChildren();
			int srcSize = srcChildElements.size();
			int desSize = desChildElements.size();
			// 源和目标元素的子元素个数是否相同
			if (srcSize != desSize) {
				result = false;
			} else {
				if (srcSize == 0) {// 源和目标没子元素且各属性相同
					result = true;
				} else {
					for (int i = 0; i < srcSize; i++) {// 比较源和目标的每个子元素
						Element srcChldElem = srcChildElements.get(i);
						Element desChldElem = desChildElements.get(i);
						if (compareElement(srcChldElem, desChldElem)) {
							result = true;
						} else {
							result = false;
							break;
						}
					}
				}
			}

		}
		return result;
	}

	/**
	 * 比较两个元素内容是否相同
	 * @param srcElem：源元素
	 * @param desElem：目标元素
	 * @return
	 */
	private boolean compareAttribute(Element srcElem, Element desElem) {
		boolean result = false;
		boolean srcHasAttributes = srcElem.hasAttributes();
		boolean desHasAttributes = desElem.hasAttributes();
		//源和目标中是否有子元素
		if (srcHasAttributes != desHasAttributes) {
			result = false;
		} else {
			if (srcHasAttributes) {
				List<Attribute> srcAttributes = srcElem.getAttributes();
				List<Attribute> desAttributes = desElem.getAttributes();
				int srcAttSize = srcAttributes.size();
				int desAttSize = desAttributes.size();
				if (srcAttSize != desAttSize) {
					result = false;
				} else {
					for (int i = 0; i < srcAttSize; i++) {
						Attribute srcAttribute = srcAttributes.get(i);
						Attribute desAttribute = desAttributes.get(i);
						boolean isNameEqual=srcAttribute.getName().equals(
								desAttribute.getName());
						boolean isValueEqual=srcAttribute.getValue().equals(
								desAttribute.getValue());
						if ( isNameEqual &&  isValueEqual){
								result = true;
						} else {
							result = false;
							break;
						}
					}
				}
			} else {
				result = true;
			}
		}
		return result;
	}
}
